/*
 *  DecryptFinal.c
 *
 *  Implementing rsa public key decryption
 *
 *  Created on: April/13/2011
 *          by: Arash Molavi Kakhki <arash@ccs.neu.edu>   
 */

#include <stdio.h>
#include <stdlib.h>
#include <openssl/rsa.h>
#include <openssl/engine.h>

#define rsaKeySize 1024
#define PubKeySize 128


void usage() {
    printf("usage: ./DecryptFinal [Source (cipher)] [Private Key] [Destination (plain)] \n");
}


int main(int argc, char *argv[]) 
{ 

	if(argc != 4) {
        	usage();
        	exit(1);
    	}

	char *Source;
	char *PriKey;
	char *Destination;

	int DecryptedBlkSize;
	int CiphertextSize;
	int CipherBlkRead;
	int max = PubKeySize - 11;
	int NumberOfBlocks,j;
	int TotalDecryptedSize = 0;

	FILE *Plaintext;
	FILE *Ciphertext;		

	Source      = argv[1];
	PriKey 	    = argv[2];
	Destination = argv[3];


/****************************************************************************************************/
/* Reading the private key
/****************************************************************************************************/
	FILE *keyfile = fopen(PriKey, "r");
   	RSA  *rsa     = PEM_read_RSAPrivateKey(keyfile, NULL, NULL, NULL);
	
	
/****************************************************************************************************/
/* Calculating the ciphertext size, number of blocks and allocating memory
/****************************************************************************************************/	
	Ciphertext = fopen(Source , "r");
	
	fseek(Ciphertext, 0L, SEEK_END);
	CiphertextSize = ftell(Ciphertext);
	fseek(Ciphertext, 0L, SEEK_SET);

	NumberOfBlocks = CiphertextSize/PubKeySize;

	unsigned char *encrypted1 = (unsigned char *) malloc(CiphertextSize);
	unsigned char *decrypted  = (unsigned char *) malloc(NumberOfBlocks*max);	

	printf("\n\nCiphertext's size: %d \n", CiphertextSize);
	printf("Number of blocks: %d \n" , NumberOfBlocks);


/****************************************************************************************************/
/* Decryption process
/****************************************************************************************************/
	printf("\nDecryption Started");

	Plaintext = fopen(Destination , "w");

	for (j = 1; j < NumberOfBlocks+1; j++){

		CipherBlkRead    = fread(encrypted1, 1, PubKeySize, Ciphertext);
		DecryptedBlkSize = RSA_private_decrypt(CipherBlkRead, encrypted1, decrypted, rsa, RSA_PKCS1_PADDING);

		if (DecryptedBlkSize == -1){
    			printf("Decryption failed\n");
    			RSA_free(rsa);
    			return 0;
			}
		else{
			printf(".");
			fflush(NULL);
			TotalDecryptedSize = TotalDecryptedSize + DecryptedBlkSize;
			decrypted 	   = decrypted + DecryptedBlkSize;			
			}	
	}	

	decrypted = decrypted - TotalDecryptedSize;

	fwrite(decrypted, 1, TotalDecryptedSize, Plaintext);

	printf("\nDecryption finished\n");


/****************************************************************************************************/
/****************************************************************************************************/
	fclose(Ciphertext);
    	fclose(Plaintext);

	RSA_free(rsa);

    	return 1;
}

